﻿namespace Microsoft.Extensions.DependencyInjection
{
    public static partial class ServiceCollectionExtensions
    {

        /// <summary>
        /// 注入服务。
        /// </summary>
        /// <param name="mvcBuilder"></param>
        /// <param name="assemblies">额外的程序集，用于服务发现。</param>
        /// <returns></returns>
        public static IMvcBuilder AddInject(this IMvcBuilder mvcBuilder, params Assembly[] assemblies)
        {
            var assemblieCollection = new List<System.Reflection.Assembly>();
            foreach (var part in mvcBuilder.PartManager.ApplicationParts)
            {
                if (part is Microsoft.AspNetCore.Mvc.ApplicationParts.AssemblyPart assemblyPart)
                {
                    assemblieCollection.Add(assemblyPart.Assembly);
                }
            }
            assemblieCollection.AddRange(assemblies);

            App._services = mvcBuilder.Services;
            App._assemblies = assemblieCollection.Distinct().ToArray();
            List<Type> typeCollection = new();
            foreach (var assembly in App.Assemblies)
            {
                try
                {
                    var types = assembly.DefinedTypes;
                    typeCollection.AddRange(types);
                }
                catch (Exception) { }
            }
            App._effectiveTypes = typeCollection.ToArray();

            mvcBuilder.Services.AddHostedService(sp =>
            {
                App._provider = sp;
                return sp.GetRequiredService<DefaultHostedService>();
            });

            //注入默认的服务。
            mvcBuilder.Services.AddHttpContextAccessor();
            mvcBuilder.Services.AddSingleton<DefaultHostedService>();
            mvcBuilder.Services.AddSingleton<IEventBus, Seagull.EventBus.EventBus>();
            mvcBuilder.Services.AddSingleton<ICacheParameterInterpreter, Seagull.Aop.CacheParameterInterpreter>();
            return mvcBuilder;
        }

        /// <summary>
        /// 扫描IOC标识出来的服务类，并动态注入到容器中。
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection ScanDependencyInjection(this IServiceCollection services)
        {
            return ScanDependencyInjection(services, (x) => { });
        }
        /// <summary>
        /// 扫描IOC标识出来的服务类，并动态注入到容器中。
        /// </summary>
        public static IServiceCollection ScanDependencyInjection(this IServiceCollection services, Action<ScanDependencyInjectionDefinition> action)
        {
            var interfacedeclaration = new Type[] { typeof(IScoped), typeof(ISingleton), typeof(ITransient), typeof(IScoped<>), typeof(ISingleton<>), typeof(ITransient<>) };
            var ignoredeclaration = interfacedeclaration.Union(new Type[] { typeof(ScopedAttribute), typeof(SingletonAttribute), typeof(TransientAttribute) });
            var types = App._effectiveTypes.Except(ignoredeclaration);

            var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
            var implementTypes = types
                .Where(type => type.IsClass)
                .Where(type => type.GetInterfaces().Select(x => x.IsGenericType ? x.GetGenericTypeDefinition() : x).Intersect(interfacedeclaration).Any() || type.GetCustomAttributes(false).Where(x => x is BaseDependencyAttribute).Any());

            foreach (var implementType in implementTypes)
            {
                List<Type> serviceTypeCollection = new(); //收集需要注册的接口
                var interfaces = implementType.GetInterfaces();//该类所实现的所有接口
                var userinterfaces = implementType.BaseType == typeof(object) ? interfaces : interfaces.Intersect(interfaceTypes);//如果该类继承了基类，只负责注册内置的类，否则注册该类实现的所有接口。                
                var genericTypeDefinition = interfaces.Where(t => t.IsGenericType).Select(t => t.GetGenericTypeDefinition());//该类所实现的泛型的接口
                var dependency = implementType.GetCustomAttributes(false).Where(x => x is BaseDependencyAttribute).FirstOrDefault();//该类所标记的注入特性

                //确定注入的方式
                bool IsScoped = false;
                bool IsSingleton = false;
                bool IsTransient = false;
                if (dependency is TransientAttribute || interfaces.Contains(typeof(ITransient)) || genericTypeDefinition.Contains(typeof(ITransient<>)))
                    IsTransient = true;
                else if (dependency is ScopedAttribute || interfaces.Contains(typeof(IScoped)) || genericTypeDefinition.Contains(typeof(IScoped<>)))
                    IsScoped = true;
                else if (dependency is SingletonAttribute || interfaces.Contains(typeof(ISingleton)) || genericTypeDefinition.Contains(typeof(ISingleton<>)))
                    IsSingleton = true;

                //确定注入的接口
                if (dependency is TransientAttribute transient)
                {
                    if (transient.BaseType is not null)
                        serviceTypeCollection.Add(transient.BaseType);
                    else
                        serviceTypeCollection.AddRange(userinterfaces);
                }
                else if (dependency is ScopedAttribute scoped)
                {
                    if (scoped.BaseType is not null)
                        serviceTypeCollection.Add(scoped.BaseType);
                    else
                        serviceTypeCollection.AddRange(userinterfaces);
                }
                else if (dependency is SingletonAttribute singleton)
                {
                    if (singleton.BaseType is not null)
                        serviceTypeCollection.Add(singleton.BaseType);
                    else
                        serviceTypeCollection.AddRange(userinterfaces);
                }
                else if (interfaces.Contains(typeof(ITransient)) || interfaces.Contains(typeof(IScoped)) || interfaces.Contains(typeof(ISingleton)))
                {
                    serviceTypeCollection.AddRange(userinterfaces);
                }
                else if (genericTypeDefinition.Contains(typeof(ITransient<>)) || genericTypeDefinition.Contains(typeof(IScoped<>)) || genericTypeDefinition.Contains(typeof(ISingleton<>)))
                {
                    foreach (var item in interfaces.Where(t => t.IsGenericType))
                    {
                        var type = item.GetGenericTypeDefinition();
                        if (type == typeof(ITransient<>) || type == typeof(IScoped<>) || type == typeof(ISingleton<>))
                        {
                            serviceTypeCollection.Add(item.GenericTypeArguments[0]);
                        }
                    }
                }

                //如果没有实现任何接口，则将自身作为服务进行注册
                if (serviceTypeCollection.Count == 0)
                {
                    serviceTypeCollection.Add(implementType);
                }

                //开始注册服务
                var args = new ScanDependencyInjectionDefinition(implementType);
                args.Services.AddRange(serviceTypeCollection);
                action?.Invoke(args);
                foreach (var serviceType in args.Services)
                {
                    if (IsScoped)
                        services.AddScoped(serviceType, implementType);
                    else if (IsSingleton)
                        services.AddSingleton(serviceType, implementType);
                    else if (IsTransient)
                        services.AddTransient(serviceType, implementType);
                }
            }
            return services;
        }
    }
}
